package logger

import (
	"context"
	"log/slog"
	"sync"

	gormlog "gorm.io/gorm/logger"
)

const (
	defaultAddSource  = false          // 默认 false   ( 保持与 slog 一致 )
	defaultCallerSkip = 3              // 默认 3 ( 最小3, 保持与 slog 一致 )
	defaultLogLevel   = slog.LevelInfo // 默认 slog.LevelInfo  ( 保持与 slog 一致 )
)

var (
	logInstanceMu sync.RWMutex
	logInstances  = make([]*Logger, 0, 1) // 日志实例缓存, 以支持全局 SyncAll 和 CloseAll
)

type Logger struct {
	handlerAgent *handlerAgent // Handler 日志控制器
}

// Options like slog.Options
type Options struct {
	Level       slog.Level                                   // 日志记录级别, 默认 slog.LevelInfo
	AddSource   bool                                         // 是否记录日志来源Source信息(1条runtime.Callers), 默认 true
	CallerSkip  int                                          // 日志来源Source信息 跳过Callers的层数, 默认 3(与slog保持一致), 如不为3, Handler.Handle()接口会依据Skip层数重写覆盖 Record.PC 埋点
	ReplaceAttr func(groups []string, a slog.Attr) slog.Attr // 自定义日志 Attr 键值对内容（即日志记录中附加的 key/value）, 默认 nil
}

// NewJson 创建Json格式的日志实例
//   - s: Storager 存储接口
//   - opts: Options 日志处理选项
func NewJson(s Storager, opts *Options) *Logger {
	if s == nil {
		panic("logger.NewJson: Storager must not be nil")
	}
	l := new(Logger)
	l.handlerAgent = newJsonHandler(s, opts)
	pushInstances(l)
	return l
}

// NewText 创建Text格式的日志实例
//   - s: Storager 存储接口
//   - opts: Options 日志处理选项
func NewText(s Storager, opts *Options) *Logger {
	if s == nil {
		panic("logger.NewText: Storager must not be nil")
	}
	l := new(Logger)
	l.handlerAgent = newTextHandler(s, opts)
	pushInstances(l)
	return l
}
func pushInstances(log *Logger) {
	logInstanceMu.Lock()
	defer logInstanceMu.Unlock()
	logInstances = append(logInstances, log)
}

// Error 记录错误日志
func (l *Logger) Error(msg string, args ...any) {
	l.handlerAgent.log(context.Background(), LevelError, msg, args...)
}

// ErrorContext 记录错误日志
func (l *Logger) ErrorContext(ctx context.Context, msg string, args ...any) {
	l.handlerAgent.log(ctx, LevelError, msg, args...)
}

// Warn 记录警告日志
func (l *Logger) Warn(msg string, args ...any) {
	l.handlerAgent.log(context.Background(), LevelWarn, msg, args...)
}

// WarnContext 记录警告日志
func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any) {
	l.handlerAgent.log(ctx, LevelWarn, msg, args...)
}

// Info 记录普通日志
func (l *Logger) Info(msg string, args ...any) {
	l.handlerAgent.log(context.Background(), LevelInfo, msg, args...)
}

// InfoContext 记录普通日志
func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any) {
	l.handlerAgent.log(ctx, LevelInfo, msg, args...)
}

// Debug 记录调试日志
func (l *Logger) Debug(msg string, args ...any) {
	l.handlerAgent.log(context.Background(), LevelDebug, msg, args...)
}

// DebugContext 记录调试日志
func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any) {
	l.handlerAgent.log(ctx, LevelDebug, msg, args...)
}

// Log 记录自定义日志
func (l *Logger) Log(ctx context.Context, level slog.Level, msg string, args ...any) {
	l.handlerAgent.log(ctx, level, msg, args...)
}

// LogAttrs 记录结构化的自定义日志
func (l *Logger) LogAttrs(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) {
	l.handlerAgent.logAttrs(ctx, level, msg, attrs...)
}

// Handler 获取日志实例Handler处理器
func (l *Logger) Handler() slog.Handler {
	return l.handlerAgent
}

// With 从现有的 handler 创建一个新的 handler，并将新增属性附加到新的 handler
func (l *Logger) With(args ...any) *Logger {
	if len(args) == 0 {
		return l
	}
	c := &Logger{}
	c.handlerAgent = l.handlerAgent.clone()
	c.handlerAgent.withAttrs = append(c.handlerAgent.withAttrs, argsToAttrSlice(args)...)
	// handlerAgent 代理了 With/WithAttrs 以支持中间件, 这里保留原有 Handler, 避免重复 WithAttrs
	// - slog 原生方式预编码了WithAttrs, 导致中间件无法读取到 WithAttrs 数据
	// - 如重复使用 handler.WithAttrs  导致 Attrs 重复追加
	// c.handlerAgent.handler = c.handlerAgent.WithAttrs(attrs)
	return c
}

const badKey = "!BADKEY"

// argsToAttr turns a prefix of the nonempty args slice into an Attr
// and returns the unconsumed portion of the slice.
// If args[0] is an Attr, it returns it.
// If args[0] is a string, it treats the first two elements as
// a key-value pair.
// Otherwise, it treats args[0] as a value with a missing key.
func argsToAttr(args []any) (slog.Attr, []any) {
	switch x := args[0].(type) {
	case string:
		if len(args) == 1 {
			return slog.String(badKey, x), nil
		}
		return slog.Any(x, args[1]), args[2:]

	case slog.Attr:
		return x, args[1:]

	default:
		return slog.Any(badKey, x), args[1:]
	}
}
func argsToAttrSlice(args []any) []slog.Attr {
	var (
		attr  slog.Attr
		attrs []slog.Attr
	)
	for len(args) > 0 {
		attr, args = argsToAttr(args)
		attrs = append(attrs, attr)
	}
	return attrs
}

// WithGroup 从现有的 handler 创建一个新的 handler，并将指定分组附加到新的 handler
func (l *Logger) WithGroup(name string) *Logger {
	if len(name) == 0 {
		return l
	}
	c := &Logger{}
	c.handlerAgent = l.handlerAgent.clone()
	c.handlerAgent.handler = c.handlerAgent.WithGroup(name)
	return c
}

// -------------------------
// 实现 中间件 接口
// -------------------------

// Use 添加中间件, 返回新的日志实例
func (l *Logger) Use(fns ...Middleware) *Logger {
	if len(fns) == 0 {
		return l
	}
	c := &Logger{}
	c.handlerAgent = l.handlerAgent.use(fns...)
	return c
}

// -------------------------
// 实现 slog Wrapper 接口
// -------------------------

// Wrap slog.log(...) Wrap 日志入口, 支持临时自定义callerSkip
func (l *Logger) Wrap(skip int, ctx context.Context, level slog.Level, msg string, args ...any) error {
	return l.handlerAgent.Wrap(skip, ctx, level, msg, args...)
}

// WrapAttrs slog.logAttrs(...) WrapAttrs 日志入口, 支持临时自定义callerSkip
func (l *Logger) WrapAttrs(skip int, ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) error {
	return l.handlerAgent.WrapAttrs(skip, ctx, level, msg, attrs...)
}

// GetOptions 获取日志选项
func (l *Logger) GetOptions() Options {
	return *l.handlerAgent.options
}

// OnClose 注册关闭事件处理器
func (l *Logger) OnClose(fn Event) {
	l.handlerAgent.OnClose(fn)
}

// OnError 注册错误事件处理器
func (l *Logger) OnError(fn Event) {
	l.handlerAgent.OnError(fn)
}

// SetLevel 设置日志等级(支持动态切换日志等级)
func (l *Logger) SetLevel(level slog.Level) {
	l.handlerAgent.SetLevel(level)
}

// GetLevel 获取日志等级
func (l *Logger) GetLevel() slog.Level {
	return l.handlerAgent.logLevel.Level()
}

// SetCallerSkip 设置日志记录 callerSkip
func (l *Logger) SetCallerSkip(skip int) {
	l.handlerAgent.SetCallerSkip(skip)
}

// GetCallerSkip 获取日志记录 callerSkip
func (l *Logger) GetCallerSkip() int {
	return l.handlerAgent.GetCallerSkip()
}

// Sync  同步 Storage缓冲区执行Buffer/Flush操作(仅同步/不关闭)
//   - 具体实现取决于日志Storage存储器
func (l *Logger) Sync() error {
	return l.handlerAgent.Sync()
}

// Close 关闭 Storage (先同步/再关闭), 关闭后将不再接受日志记录
//   - 具体实现取决于日志Storage存储器
func (l *Logger) Close() error {
	return l.handlerAgent.Close()
}

// IsClose 日志 Storage 是否已关闭
func (l *Logger) IsClose() bool {
	return l.handlerAgent.IsClose()
}

// LastErrors 获取 Handler及Storage 最近的错误信息
func (l *Logger) LastErrors() error {
	return l.handlerAgent.LastErrors()
}

// ToSlog 转换 Logger 为 *slog.Logger
//   - 注意：原 Logger 自定义等级/调整等级/中间件/同步/关闭行为均为影响转换后的 *slog.Logger
func (l *Logger) ToSlog() *slog.Logger {
	return ToSlog(l)
}

// ToGinLogger 转换 Logger 为 gin.LoggerWriter
//   - 注意：原 Logger 自定义等级/调整等级/中间件/同步/关闭行为均为影响转换后的 *ginLogger
func (l *Logger) ToGinLogger() *ginLogger {
	return ToGinLogger(l)
}

// ToGormLogger 转换 Logger 为gormlog.Interface
//   - 注意：原 Logger 自定义等级/调整等级/中间件/同步/关闭行为均为影响转换后的 *gormLogger
func (l *Logger) ToGormLogger() gormlog.Interface {
	return ToGormLogger(l)
}
